#include "lua_binding.h"
#include "lauxlib.h"
#include "app_log.h"
#include <string.h>

#include "lua_module_log.h" // Include the header for our new module
#include "lua_module_mcu.h"
#include "lua_module_gpio.h"
#include "lua_module_timer.h"
#include "lua_module_fs.h"
#include "lua_module_net.h"
#include "lua_module_mqtt.h"
#include "lua_module_uart.h"
#include "lua_module_sim.h"
#include "lua_module_ntp.h"
#include "lua_module_http.h"
#include "lua_module_sys.h"

// Custom implementation for Lua's print function
static int ml307c_print(lua_State *L)
{
    int n = lua_gettop(L); // Number of arguments
    int i;
    lua_getglobal(L, "tostring");

    char log_buffer[256] = {0};
    char *buf_ptr = log_buffer;
    int remaining = sizeof(log_buffer) - 1; // leave space for null terminator

    for (i = 1; i <= n; i++)
    {
        const char *s;
        size_t l;

        lua_pushvalue(L, -1); // Push 'tostring' function
        lua_pushvalue(L, i);  // Push the argument
        lua_call(L, 1, 1);    // Call tostring(arg)

        s = lua_tolstring(L, -1, &l);
        if (s == NULL) {
             lua_pop(L, 1); // pop nil
             continue;
        }

        if (i > 1 && remaining > 0) {
            *buf_ptr++ = '\t';
            remaining--;
        }

        int to_copy = (l < remaining) ? l : remaining;
        if (to_copy > 0) {
            memcpy(buf_ptr, s, to_copy);
            buf_ptr += to_copy;
            remaining -= to_copy;
        }

        lua_pop(L, 1); // Pop the string result
    }

    *buf_ptr = '\0';
    app_log_printf("[LUA] %s", log_buffer);

    return 0;
}


// Entry point for all custom libraries
int luaopen_ml307c_libs(lua_State *L)
{
    // Override print function
    lua_pushcfunction(L, ml307c_print);
    lua_setglobal(L, "print");

    // Load the log library
    luaL_requiref(L, "log", luaopen_log, 1);
    lua_pop(L, 1);

    // Load the mcu library
    luaL_requiref(L, "mcu", luaopen_mcu, 1);
    lua_pop(L, 1);

    // Load the gpio library
    luaL_requiref(L, "gpio", luaopen_gpio, 1);
    lua_pop(L, 1);

    // Load the timer library
    luaL_requiref(L, "timer", luaopen_timer, 1);
    lua_pop(L, 1);

    // Load the fs library
    luaL_requiref(L, "fs", luaopen_fs, 1);
    lua_pop(L, 1);

    // Load the net library
    luaL_requiref(L, "net", luaopen_net, 1);
    lua_pop(L, 1);

    // Load the mqtt library
    luaL_requiref(L, "mqtt", luaopen_mqtt, 1);
    lua_pop(L, 1);

    // Load the uart library
    luaL_requiref(L, "uart", luaopen_uart, 1);
    lua_pop(L, 1);

    // Load the sim library
    luaL_requiref(L, "sim", luaopen_sim, 1);
    lua_pop(L, 1);

    // Load the ntp library
    luaL_requiref(L, "ntp", luaopen_ntp, 1);
    lua_pop(L, 1);

    // Load the http library
    luaL_requiref(L, "http", luaopen_http, 1);
    lua_pop(L, 1);
    luaL_requiref(L, "sys", luaopen_sys, 1);
    lua_pop(L, 1);

    return 1;
}
